package com.whmskj.xjlhsc.mobie.personnelFile.service.impl;

import com.whmskj.xjlhsc.mobie.personnelFile.dto.LeaveApplicationDetailDTO;
import com.whmskj.xjlhsc.mobie.personnelFile.mapper.LeaveApplicationMapper;
import com.whmskj.xjlhsc.mobie.personnelFile.mapper.EmployeeProfileMapper;
import com.whmskj.xjlhsc.mobie.personnelFile.dto.LeaveApplicationListDTO;
import com.whmskj.xjlhsc.mobie.personnelFile.mapper.ApprovalRecordMapper;
import com.whmskj.xjlhsc.mobie.personnelFile.mapper.ApprovalRuleMapper;
import com.whmskj.xjlhsc.mobie.personnelFile.entity.ApprovalRecord;
import com.whmskj.xjlhsc.mobie.personnelFile.service.LeaveApplicationService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class LeaveApplicationServiceImpl implements LeaveApplicationService {

    private static final List<String> TYPES = Arrays.asList("事假", "病假", "年假", "婚假", "产假", "丧假", "事故", "调休");

    @Override
    public List<String> leaveTypes() {
        return TYPES;
    }


    @Autowired
    private EmployeeProfileMapper employeeProfileMapper;
    @Autowired
    private LeaveApplicationMapper mapper;
    @Autowired
    private ApprovalRecordMapper approvalRecordMapper;
    @Autowired
    private ApprovalRuleMapper approvalRuleMapper;

    @Override
    public Map<String, Object> currentEmployeeProfileByUserId(String userId) {
        if (userId == null || userId.trim().isEmpty()) return null;
        return employeeProfileMapper.selectEmployeeByUserId(userId);
    }


    @Override
    public List<Map<String, Object>> searchEmployees(String keyword, Integer limit) {
        if (limit == null || limit <= 0) limit = 20;
        return mapper.searchEmployees(keyword, limit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int create(Map<String, Object> payload, boolean submit) {
        Objects.requireNonNull(payload, "payload is null");
        // 基本校验
        Integer employeeId = asInt(payload.get("employee_id"));
        if (employeeId == null) throw new IllegalArgumentException("员工ID必填");
        LocalDateTime start = asDateTime(payload.get("start_time"));
        LocalDateTime end = asDateTime(payload.get("end_time"));
        if (start == null || end == null) throw new IllegalArgumentException("开始/结束时间必填");
        if (!end.isAfter(start)) throw new IllegalArgumentException("结束时间必须大于开始时间");
        String leaveType = asStr(payload.get("leave_type"));
        if (leaveType == null || leaveType.isEmpty()) throw new IllegalArgumentException("请假类型必填");

        // 计算请假天数并校验
        BigDecimal days = calcDays(start, end);
        if (days.compareTo(BigDecimal.ONE) < 0) {
            throw new IllegalArgumentException("请假天数不能少于1天，当前计算天数为：" + days + "天");
        }
        if (days.compareTo(new BigDecimal("365")) > 0) {
            throw new IllegalArgumentException("请假天数不能超过365天，当前天数为：" + days + "天");
        }

        // 员工冗余字段补齐（从员工档案表查询，并转换为请假表字段名）
        Map<String, Object> emp = employeeProfileMapper.selectEmployeeById(employeeId);
        if (emp == null) throw new IllegalArgumentException("员工不存在: " + employeeId);
        payload.put("employee_name", emp.get("name"));
        payload.put("employee_code", emp.get("code"));
        payload.put("employee_dept", emp.get("sector"));

        // 设置请假天数（已在上面校验过）
        payload.put("leave_days", days);

        // 处理图片：数组转逗号
        Object imgs = payload.get("proof_images");
        if (imgs instanceof List) {
            @SuppressWarnings("unchecked")
            List<String> list = (List<String>) imgs;
            payload.put("proof_images", String.join(",", list));
        }

        // 状态与首节点指派（提交时）
        if (submit) {
            payload.put("status", "审核中");
            payload.put("application_time", LocalDateTime.now());
            // 指派当前审批人：优先班长(classes)，若没有则指派主任(firstlevelReviewerForRewardsAndS)
            Integer classLeaderId = tryParseId(emp.get("classes"));
            Integer directorId = tryParseId(emp.get("firstlevelReviewerForRewardsAndS"));
            Integer approverId = classLeaderId != null ? classLeaderId : directorId;
            if (approverId != null) {
                Map<String, Object> approver = employeeProfileMapper.selectEmployeeById(approverId);
                if (approver != null) {
                    payload.put("current_approver_id", approverId);
                    payload.put("current_approver_name", approver.get("name"));
                }
            }
        } else {
            payload.put("status", "待审核");
        }

        return mapper.insert(payload);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDraft(Integer id, Map<String, Object> payload) {
        if (id == null) throw new IllegalArgumentException("id 必填");

        // 先检查记录是否存在
        com.whmskj.xjlhsc.mobie.personnelFile.dto.LeaveApplicationDetailDTO existingRecord = mapper.selectById(id);
        if (existingRecord == null) {
            throw new IllegalArgumentException("请假申请不存在，ID: " + id);
        }

        payload = payload == null ? new HashMap<>() : new HashMap<>(payload);
        payload.put("application_id", id);
        // 可选重算天数
        LocalDateTime start = asDateTime(payload.get("start_time"));
        LocalDateTime end = asDateTime(payload.get("end_time"));
        if (start != null && end != null) {
            if (!end.isAfter(start)) throw new IllegalArgumentException("结束时间必须大于开始时间");
            BigDecimal days = calcDays(start, end);
            if (days.compareTo(BigDecimal.ONE) < 0) {
                throw new IllegalArgumentException("请假天数不能少于1天，当前计算天数为：" + days + "天");
            }
            if (days.compareTo(new BigDecimal("365")) > 0) {
                throw new IllegalArgumentException("请假天数不能超过365天，当前天数为：" + days + "天");
            }
            payload.put("leave_days", days);
        }
        Object imgs = payload.get("proof_images");
        if (imgs instanceof List) {
            @SuppressWarnings("unchecked") List<String> list = (List<String>) imgs;
            payload.put("proof_images", String.join(",", list));
        }

        int result = mapper.updateSelective(payload);
        if (result == 0) {
            throw new IllegalArgumentException("更新失败，请假申请不存在或数据未发生变化，ID: " + id);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int submit(Integer id, Integer approverId, String approverName) {
        if (id == null) throw new IllegalArgumentException("id 必填");

        // 先检查记录是否存在
        com.whmskj.xjlhsc.mobie.personnelFile.dto.LeaveApplicationDetailDTO existingRecord = mapper.selectById(id);
        if (existingRecord == null) {
            throw new IllegalArgumentException("请假申请不存在，ID: " + id);
        }

        // 检查是否已经提交过（已有申请时间）
        if (existingRecord.getApplicationTime() != null) {
            throw new IllegalArgumentException("该申请已经提交过，不能重复提交");
        }

        // 如果未传入审批人信息，则根据请假申请人档案自动获取第一个审批人
        if (approverId == null || approverName == null) {
            Map<String, Object> applicant = employeeProfileMapper.selectEmployeeById(existingRecord.getEmployeeId());
            if (applicant == null) {
                throw new IllegalArgumentException("未找到请假申请人的员工档案");
            }

            // 根据请假天数计算审批流程，获取第一个审批节点
            BigDecimal leaveDays = existingRecord.getLeaveDays() == null ? null : BigDecimal.valueOf(existingRecord.getLeaveDays());
            List<String> flow = computeFlowByDays(leaveDays);
            if (flow.isEmpty()) {
                throw new IllegalArgumentException("无法确定审批流程");
            }

            String firstNode = flow.get(0);
            Integer firstApproverId = null;
            String firstApproverName = null;

            // 根据第一个审批节点获取审批人
            switch (firstNode) {
                case "班长":
                    firstApproverId = tryParseId(applicant.get("classes"));
                    break;
                case "主任":
                    firstApproverId = tryParseId(applicant.get("firstlevelReviewerForRewardsAndS"));
                    break;
                case "厂长助理":
                    firstApproverId = getFactoryAssistantId((String) applicant.get("sector"));
                    break;
                case "厂长":
                    firstApproverId = getFactoryManagerId((String) applicant.get("sector"));
                    break;
                case "总经理":
                    firstApproverId = getGeneralManagerId();
                    break;
            }

            if (firstApproverId != null) {
                Map<String, Object> approver = employeeProfileMapper.selectEmployeeById(firstApproverId);
                if (approver != null) {
                    firstApproverName = String.valueOf(approver.get("name"));
                }
            }

            if (firstApproverId == null || firstApproverName == null) {
                throw new IllegalArgumentException("无法确定第一个审批人，节点: " + firstNode);
            }

            approverId = firstApproverId;
            approverName = firstApproverName;
        }

        // 更新状态并设置申请时间
        Map<String, Object> updateData = new HashMap<>();
        updateData.put("application_id", id);
        updateData.put("application_time", LocalDateTime.now().toString());
        updateData.put("status", "审核中");
        updateData.put("current_approver_id", approverId);
        updateData.put("current_approver_name", approverName);

        int result = mapper.updateSelective(updateData);
        if (result == 0) {
            throw new IllegalArgumentException("提交失败，请假申请不存在，ID: " + id);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cancel(Integer id, String cancelReason) {
        if (id == null) throw new IllegalArgumentException("id 必填");

        // 先检查记录是否存在
        LeaveApplicationDetailDTO existingRecord = mapper.selectById(id);
        if (existingRecord == null) {
            throw new IllegalArgumentException("请假申请不存在，ID: " + id);
        }

        int result = mapper.updateStatus(id, "已撤销", cancelReason, null, null, LocalDateTime.now());
        if (result == 0) {
            throw new IllegalArgumentException("撤销失败，请假申请不存在，ID: " + id);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int approve(Integer id, Integer approverId, String approverName) {
        if (id == null) throw new IllegalArgumentException("id 必填");

        // 1. 基于档案实时字段做强校验：如审批人已变更，则自动迁移并提示
        ensureApproverUpToDate(id, approverId);

        // 2. 再检查审批权限（确保与最新档案一致）
        if (!canApprove(id, approverId)) {
            throw new IllegalArgumentException("当前用户无审批权限");
        }

        // 3. 获取当前审批节点
        String currentNode = getCurrentApprovalNode(id);
        if (currentNode == null) {
            throw new IllegalArgumentException("当前申请无需审批");
        }

        // 4. 记录审批记录
        ApprovalRecord record = new ApprovalRecord();
        record.setApplicationId(id);
        record.setApproverId(approverId);
        record.setApproverName(approverName);
        record.setApprovalNode(normalizeNodeName(currentNode));
        record.setApprovalStatus("同意");
        record.setApprovalTime(LocalDateTime.now());
        approvalRecordMapper.insert(record);

        // 5. 检查是否所有节点都已审批
        if (isAllNodesApproved(id)) {
            // 所有节点审批完成，更新状态为"审核通过"
            return mapper.updateStatus(id, "审核通过", null, approverId, approverName, LocalDateTime.now());
        } else {
            // 还有下一层级需要审批，更新当前审批人
            String nextApprover = getNextApprover(id);
            return mapper.updateStatus(id, "审核中", null, nextApprover != null ? Integer.valueOf(nextApprover) : null, null, LocalDateTime.now());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int reject(Integer id, Integer approverId, String approverName, String reason) {
        if (id == null) throw new IllegalArgumentException("id 必填");

        // 1. 基于档案实时字段做强校验：如审批人已变更，则自动迁移并提示
        ensureApproverUpToDate(id, approverId);

        // 2. 再检查审批权限
        if (!canApprove(id, approverId)) {
            throw new IllegalArgumentException("当前用户无审批权限");
        }

        // 3. 获取当前审批节点
        String currentNode = getCurrentApprovalNode(id);
        if (currentNode == null) {
            throw new IllegalArgumentException("当前申请无需审批");
        }

        // 4. 记录审批记录
        ApprovalRecord record = new ApprovalRecord();
        record.setApplicationId(id);
        record.setApproverId(approverId);
        record.setApproverName(approverName);
        record.setApprovalNode(normalizeNodeName(currentNode));
        record.setApprovalStatus("不同意");
        record.setApprovalOpinion(reason);
        record.setApprovalTime(LocalDateTime.now());
        approvalRecordMapper.insert(record);

        // 5. 更新申请状态为驳回
        return mapper.updateStatus(id, "驳回", reason, approverId, approverName, LocalDateTime.now());
    }

    @Override
    public List<LeaveApplicationListDTO> list(Integer employeeId, String employeeName, String status, LocalDateTime startFrom, LocalDateTime endTo) {
        // 这里可接 PageHelper.startPage(pageNum,pageSize)
        return mapper.selectList(employeeId, employeeName, status, startFrom, endTo);
    }

    /**
     * 列表同条件的性别统计
     */
    public Map<String, Object> listGenderSummary(Integer employeeId, String employeeName, String status, LocalDateTime startFrom, LocalDateTime endTo) {
        Map<String, Object> map = mapper.countByGender(employeeId, employeeName, status, startFrom, endTo);
        if (map == null) map = new HashMap<>();
        map.putIfAbsent("total", 0);
        map.putIfAbsent("male", 0);
        map.putIfAbsent("female", 0);
        return map;
    }

    @Override
    public LeaveApplicationDetailDTO detail(Integer id) {
        LeaveApplicationDetailDTO detail = mapper.selectById(id);
        if (detail != null) {
            // 查询审批记录
            List<Map<String, Object>> approvalRecords = approvalRecordMapper.selectByApplicationId(id);
            List<LeaveApplicationDetailDTO.ApprovalRecordDTO> recordDTOs = new ArrayList<>();

            for (Map<String, Object> record : approvalRecords) {
                LeaveApplicationDetailDTO.ApprovalRecordDTO dto = new LeaveApplicationDetailDTO.ApprovalRecordDTO();
                dto.setApprovalNode((String) record.get("approvalNode"));
                dto.setApproverName((String) record.get("approverName"));
                dto.setApprovalOpinion((String) record.get("approvalOpinion"));
                dto.setApprovalStatus((String) record.get("approvalStatus"));

                // 处理审批时间
                Object approvalTime = record.get("approvalTime");
                if (approvalTime != null) {
                    if (approvalTime instanceof LocalDateTime) {
                        dto.setApprovalTime((LocalDateTime) approvalTime);
                    } else if (approvalTime instanceof java.sql.Timestamp) {
                        dto.setApprovalTime(((java.sql.Timestamp) approvalTime).toLocalDateTime());
                    }
                }

                recordDTOs.add(dto);
            }

            detail.setApprovalRecords(recordDTOs);

            // ===== 组装流程编排增强字段 =====
            BigDecimal leaveDays = detail.getLeaveDays() == null ? null : BigDecimal.valueOf(detail.getLeaveDays());
            List<String> flow = computeFlowByDays(leaveDays);
            // 若申请人本身就是中/高层级（主任/厂长助理/总经理），则从其自身节点开始展示
            Map<String, Object> applicantForRole = employeeProfileMapper.selectEmployeeById(detail.getEmployeeId());
            String startNode = resolveApplicantStartNode(applicantForRole);
            if ("__NONE__".equals(startNode)) {
                flow = new java.util.ArrayList<>(); // 最高层（总经理）申请，无更高节点
            } else if (startNode != null && flow.contains(startNode)) {
                int idx = flow.indexOf(startNode);
                flow = new java.util.ArrayList<>(flow.subList(idx, flow.size()));
            }
            detail.setApprovalFlow(flow);

            // 已同意节点集合
            List<String> approvedNodes = approvalRecordMapper.getApprovedNodes(id);

            // 申请人档案（用于解析每节点应审批人）
            Map<String, Object> applicant = employeeProfileMapper.selectEmployeeById(detail.getEmployeeId());

            List<LeaveApplicationDetailDTO.FlowNodeDTO> nodes = new ArrayList<>();
            int done = 0;
            Integer nextApproverId = null;
            String nextApproverName = null;
            String currentNode = null;

            for (String node : flow) {
                LeaveApplicationDetailDTO.FlowNodeDTO n = new LeaveApplicationDetailDTO.FlowNodeDTO();
                n.setNode(node);

                // 解析节点应审批人
                Integer approverId = null;
                switch (node) {
                    case "班组":
                    case "班长":
                        approverId = tryParseId(applicant.get("classes"));
                        break;
                    case "部门经理":
                    case "主任":
                        approverId = tryParseId(applicant.get("firstlevelReviewerForRewardsAndS"));
                        break;
                    case "厂长助理":
                        approverId = getFactoryAssistantId((String) applicant.get("sector"));
                        break;
                    case "厂长":
                        approverId = getFactoryManagerId((String) applicant.get("sector"));
                        break;
                    case "总经理":
                        approverId = getGeneralManagerId();
                        break;
                }
                n.setApproverId(approverId);
                if (approverId != null) {
                    Map<String, Object> emp = employeeProfileMapper.selectEmployeeById(approverId);
                    if (emp != null) n.setApproverName(String.valueOf(emp.get("name")));
                }

                // 填充轨迹状态
                Optional<LeaveApplicationDetailDTO.ApprovalRecordDTO> record = recordDTOs.stream()
                        .filter(r -> {
                            String nodeName = r.getApprovalNode();
                            if (nodeName == null) return false;
                            return node.equals(nodeName);
                        })
                        .findFirst();
                if (record.isPresent()) {
                    String status = "同意".equals(record.get().getApprovalStatus()) ? "approved" : "rejected";
                    n.setStatus(status);
                    n.setApprovalTime(record.get().getApprovalTime());
                    n.setOpinion(record.get().getApprovalOpinion());
                    if ("approved".equals(status)) done++;
                } else {
                    n.setStatus("pending");
                    if (currentNode == null) {
                        currentNode = node;
                        nextApproverId = approverId;
                        nextApproverName = n.getApproverName();
                    }
                }
                nodes.add(n);
            }

            detail.setNodes(nodes);
            detail.setProgress(done);
            detail.setCurrentNode(currentNode);
            detail.setNextApproverId(nextApproverId);
            detail.setNextApproverName(nextApproverName);
        }
        return detail;
    }

    @Override
    public List<LeaveApplicationListDTO> listMine(Integer myEmployeeId, String employeeName, String status, LocalDateTime startFrom, LocalDateTime endTo) {
        return mapper.selectList(myEmployeeId, employeeName, status, startFrom, endTo);
    }

    @Override
    public List<LeaveApplicationListDTO> listAllView(Integer myEmployeeId, String employeeName, LocalDateTime startFrom, LocalDateTime endTo) {
        // 他人已审核 + 我的全部：
        return mapper.selectAllView(myEmployeeId, employeeName, startFrom, endTo);
    }

    @Override
    public List<LeaveApplicationListDTO> listPendingForApprover(Integer approverId, String employeeName, LocalDateTime startFrom, LocalDateTime endTo) {
        List<LeaveApplicationListDTO> rows = mapper.selectPendingForApprover(approverId, employeeName, startFrom, endTo);
        return rows; // Controller 层将进行 DTO 映射
    }

    @Override
    public List<LeaveApplicationListDTO> listHandledByMe(Integer myEmployeeId, String result, String employeeName, LocalDateTime startFrom, LocalDateTime endTo) {
        return mapper.selectHandledByMe(myEmployeeId, result, employeeName, startFrom, endTo);
    }

    /**
     * 节点名称归一化：统一把“厂长”存为“厂长助理”
     */
    private String normalizeNodeName(String node) {
        if (node == null) return null;
        return "厂长".equals(node) ? "厂长助理" : node;
    }

    private static BigDecimal calcDays(LocalDateTime start, LocalDateTime end) {
        if (start == null || end == null) {
            throw new IllegalArgumentException("开始时间和结束时间不能为空");
        }

        if (!end.isAfter(start)) {
            throw new IllegalArgumentException("结束时间必须大于开始时间");
        }

        // 按天计算：结束日期 - 开始日期 + 1天
        long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(start.toLocalDate(), end.toLocalDate()) + 1;

        // 最少请假天数：1天
        if (daysBetween < 1) {
            throw new IllegalArgumentException("请假天数不能少于1天");
        }

        return BigDecimal.valueOf(daysBetween);
    }

    private static Integer asInt(Object o) {
        if (o == null) return null;
        if (o instanceof Number) return ((Number) o).intValue();
        return Integer.valueOf(String.valueOf(o));
    }

    /**
     * 将档案中的审批人字段解析为ID：
     * - 如果是数字/字符串数字：直接转为ID
     * - 如果是中文姓名：按姓名去员工档案匹配，取其ID
     */
    private Integer tryParseId(Object value) {
        if (value == null) return null;
        if (value instanceof Number) return ((Number) value).intValue();
        String s = String.valueOf(value).trim();
        if (s.isEmpty()) return null;
        try {
            return Integer.valueOf(s);
        } catch (Exception ignore) {
            // 非数字，按姓名匹配员工
            Map<String, Object> found = employeeProfileMapper.selectEmployeeByName(s);
            return found == null ? null : asInt(found.get("id"));
        }
    }

    private static LocalDateTime asDateTime(Object o) {
        if (o == null) return null;
        if (o instanceof LocalDateTime) return (LocalDateTime) o;

        String s = String.valueOf(o).trim();
        if (s.isEmpty()) return null;

        try {
            // 请假申请只支持 "yyyy-MM-dd" 格式，自动转换为 00:00:00
            java.time.format.DateTimeFormatter f = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd");
            java.time.LocalDate date = java.time.LocalDate.parse(s, f);
            return date.atStartOfDay();
        } catch (Exception e) {
            throw new IllegalArgumentException("请假日期格式错误，请使用 yyyy-MM-dd 格式，如：2025-01-15");
        }
    }

    private static String asStr(Object o) {
        return o == null ? null : String.valueOf(o);
    }

    /**
     * 检查用户是否有审批权限
     */
    private boolean canApprove(Integer applicationId, Integer approverId) {
        // 1. 获取请假申请信息
        LeaveApplicationDetailDTO application = mapper.selectById(applicationId);
        if (application == null) {
            return false;
        }

        // 2. 获取当前应该审批的节点
        String currentNode = getCurrentApprovalNode(applicationId);
        if (currentNode == null) {
            return false;
        }

        // 3. 检查审批人是否有对应角色的审批权限
        return checkApproverRole(approverId, currentNode, application);
    }

    /**
     * 获取当前应该审批的节点
     */
    private String getCurrentApprovalNode(Integer applicationId) {
        // 1. 获取审批流程
        List<String> approvalFlow = getApprovalFlow(applicationId);
        if (approvalFlow == null || approvalFlow.isEmpty()) {
            return null;
        }

        // 2. 获取已审批的节点
        List<String> approvedNodes = approvalRecordMapper.getApprovedNodes(applicationId);

        // 3. 找到第一个未审批的节点
        for (String node : approvalFlow) {
            if (!approvedNodes.contains(node)) {
                return node;
            }
        }

        return null; // 所有节点都已审批
    }

    /**
     * 根据请假申请获取审批流程
     */
    private List<String> getApprovalFlow(Integer applicationId) {
        // 1. 获取请假申请信息
        LeaveApplicationDetailDTO application = mapper.selectById(applicationId);
        if (application == null) {
            return null;
        }
        // 2. 按请假天数决定审批层级
        Integer leaveDaysInt = application.getLeaveDays();
        BigDecimal leaveDays = leaveDaysInt == null ? null : BigDecimal.valueOf(leaveDaysInt);
        return computeFlowByDays(leaveDays);
    }

    private List<String> computeFlowByDays(BigDecimal leaveDays) {
        if (leaveDays == null) {
            // 默认流程：班长 -> 主任
            return Arrays.asList("班长", "主任");
        }

        // 确保请假天数为正数
        if (leaveDays.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("请假天数必须大于0天");
        }

        int cmp2 = leaveDays.compareTo(new BigDecimal("2"));
        int cmp7 = leaveDays.compareTo(new BigDecimal("7"));

        if (cmp2 <= 0) {
            // 0 < 天数 <= 2天：班长 -> 主任
            return Arrays.asList("班长", "主任");
        } else if (cmp2 > 0 && cmp7 <= 0) {
            // 2天 < 天数 <= 7天：班长 -> 主任 -> 厂长助理
            return Arrays.asList("班长", "主任", "厂长助理");
        } else {
            // 天数 > 7天：班长 -> 主任 -> 厂长助理 -> 总经理
            return Arrays.asList("班长", "主任", "厂长助理", "总经理");
        }
    }

    /**
     * 根据申请人职位，确定审批流的起始节点（从申请人职位的上一级开始审核）：
     * - 班长/组长/班组 → 从“主任”开始
     * - 主任/部门经理 → 从“厂长助理”开始
     * - 厂长 → 从“总经理”开始
     * - 厂长助理 → 从“总经理”开始
     * - 总经理 → 无更高节点，返回 "__NONE__"
     */
    private String resolveApplicantStartNode(Map<String, Object> applicant) {
        if (applicant == null) return null;
        Object posObj = applicant.get("positions");
        String positions = posObj == null ? null : String.valueOf(posObj);
        if (positions == null || positions.isEmpty()) return null;
        if (positions.contains("总经理")) return "__NONE__"; // 顶级，无更高节点
        if (positions.contains("厂长助理") || positions.contains("厂长")) return "总经理";
        if (positions.contains("主任") || positions.contains("部门经理")) return "厂长助理";
        if (positions.contains("班长") || positions.contains("组长") || positions.contains("班组")) return "主任";
        return null;
    }

    /**
     * 检查审批人是否有对应角色的审批权限
     */
    private boolean checkApproverRole(Integer approverId, String approvalNode, LeaveApplicationDetailDTO application) {
        // 1. 获取审批人信息
        Map<String, Object> approver = employeeProfileMapper.selectEmployeeById(approverId);
        if (approver == null) {
            return false;
        }

        // 2. 获取申请人信息
        Integer applicantId = application.getEmployeeId();
        Map<String, Object> applicant = employeeProfileMapper.selectEmployeeById(applicantId);
        if (applicant == null) {
            return false;
        }

        // 3. 根据审批节点检查权限
        switch (approvalNode) {
            case "班长":
                // 检查是否是一级审核人（班长）——来自档案表字段 classes（可能为ID或姓名）
                Integer firstLevelApprover = tryParseId(applicant.get("classes"));
                return firstLevelApprover != null && approverId.equals(firstLevelApprover);

            case "部门经理":
            case "主任":
                // 检查是否是二级审核人（主任）——来自档案表字段 firstlevelReviewerForRewardsAndS（可能为ID或姓名）
                Integer secondLevelApprover = tryParseId(applicant.get("firstlevelReviewerForRewardsAndS"));
                return secondLevelApprover != null && approverId.equals(secondLevelApprover);

            case "厂长助理":
                return checkFactoryAssistantPermission(approverId, (String) applicant.get("sector"));

            case "总经理":
                // 检查是否是总经理（这里需要根据实际业务逻辑实现）
                return checkGeneralManagerPermission(approverId);

            default:
                return false;
        }
    }

    /**
     * 检查是否所有节点都已审批
     */
    private boolean isAllNodesApproved(Integer applicationId) {
        List<String> approvalFlow = getApprovalFlow(applicationId);
        if (approvalFlow == null || approvalFlow.isEmpty()) {
            return true;
        }

        List<String> approvedNodes = approvalRecordMapper.getApprovedNodes(applicationId);
        return approvedNodes.containsAll(approvalFlow);
    }

    /**
     * 获取下一个审批人
     */
    private String getNextApprover(Integer applicationId) {
        String nextNode = getCurrentApprovalNode(applicationId);
        if (nextNode == null) {
            return null;
        }

        // 根据节点获取对应的审批人ID
        LeaveApplicationDetailDTO application = mapper.selectById(applicationId);
        Integer applicantId = application.getEmployeeId();
        Map<String, Object> applicant = employeeProfileMapper.selectEmployeeById(applicantId);

        Integer nextApproverId = null;
        switch (nextNode) {
            case "班组":
            case "班长":
                nextApproverId = tryParseId(applicant.get("classes"));
                break;
            case "部门经理":
            case "主任":
                nextApproverId = tryParseId(applicant.get("firstlevelReviewerForRewardsAndS"));
                break;
            case "厂长助理":
                nextApproverId = getFactoryAssistantId((String) applicant.get("sector"));
                break;
            case "厂长":
                // 根据 positions=厂长 或 厂长助理 来定位厂长（优先厂长，其次厂长助理）
                nextApproverId = getFactoryManagerId((String) applicant.get("sector"));
                break;
            case "总经理":
                nextApproverId = getGeneralManagerId();
                break;
        }

        return nextApproverId != null ? nextApproverId.toString() : null;
    }

    /**
     * 确保当前审批人等于档案实时字段对应的人；若不一致，则把单据当前审批人迁移到最新人并提示。
     */
    private void ensureApproverUpToDate(Integer applicationId, Integer approverId) {
        // 获取申请与申请人
        LeaveApplicationDetailDTO application = mapper.selectById(applicationId);
        if (application == null) throw new IllegalArgumentException("请假申请不存在");
        Integer applicantId = application.getEmployeeId();
        Map<String, Object> applicant = employeeProfileMapper.selectEmployeeById(applicantId);
        if (applicant == null) throw new IllegalArgumentException("申请人档案不存在");

        // 当前节点
        String node = getCurrentApprovalNode(applicationId);
        if (node == null) return; // 无需审批

        // 计算最新应审批人
        Integer latestApproverId = null;
        switch (node) {
            case "班组":
            case "班长":
                latestApproverId = tryParseId(applicant.get("classes"));
                break;
            case "部门经理":
            case "主任":
                latestApproverId = tryParseId(applicant.get("firstlevelReviewerForRewardsAndS"));
                break;
            case "厂长助理":
                latestApproverId = getFactoryAssistantId((String) applicant.get("sector"));
                break;
            case "厂长":
                latestApproverId = getFactoryManagerId((String) applicant.get("sector"));
                break;
            case "总经理":
                latestApproverId = getGeneralManagerId();
                break;
            default:
                break;
        }

        if (latestApproverId == null) {
            throw new IllegalArgumentException("当前节点未配置审批人，请联系管理员");
        }

        if (!approverId.equals(latestApproverId)) {
            Map<String, Object> latest = employeeProfileMapper.selectEmployeeById(latestApproverId);
            String latestName = latest == null ? String.valueOf(latestApproverId) : String.valueOf(latest.get("name"));
            // 将单据指派至最新审批人
            mapper.updateStatus(applicationId, "审核中", null, latestApproverId, latestName, LocalDateTime.now());
            throw new IllegalArgumentException("审批人已变更为：" + latestName + "，请由新审批人处理");
        }
    }

    /**
     * 检查厂长权限
     */
    private boolean checkFactoryManagerPermission(Integer approverId, String department) {
        // positions 精确匹配：优先厂长，其次厂长助理
        Map<String, Object> fm = employeeProfileMapper.selectOneByPosition("厂长", department);
        if (fm != null && approverId.equals(fm.get("id"))) return true;
        Map<String, Object> assistant = employeeProfileMapper.selectOneByPosition("厂长助理", department);
        return assistant != null && approverId.equals(assistant.get("id"));
    }

    /**
     * 检查厂长助理权限
     */
    private boolean checkFactoryAssistantPermission(Integer approverId, String department) {
        Map<String, Object> assistant = employeeProfileMapper.selectOneByPosition("厂长助理", department);
        return assistant != null && approverId.equals(assistant.get("id"));
    }

    /**
     * 检查总经理权限
     */
    private boolean checkGeneralManagerPermission(Integer approverId) {
        Map<String, Object> gm = employeeProfileMapper.selectOneByPosition("总经理", null);
        return gm != null && approverId.equals(gm.get("id"));
    }

    /**
     * 获取厂长ID
     */
    private Integer getFactoryManagerId(String department) {
        Map<String, Object> fm = employeeProfileMapper.selectOneByPosition("厂长", department);
        if (fm != null) return (Integer) fm.get("id");
        Map<String, Object> assistant = employeeProfileMapper.selectOneByPosition("厂长助理", department);
        return assistant == null ? null : (Integer) assistant.get("id");
    }

    /**
     * 获取厂长助理ID
     */
    private Integer getFactoryAssistantId(String department) {
        Map<String, Object> assistant = employeeProfileMapper.selectOneByPosition("厂长助理", department);
        return assistant == null ? null : (Integer) assistant.get("id");
    }

    /**
     * 获取总经理ID
     */
    private Integer getGeneralManagerId() {
        Map<String, Object> gm = employeeProfileMapper.selectOneByPosition("总经理", null);
        return gm == null ? null : (Integer) gm.get("id");
    }
}

